# -*- coding: utf-8 -*-

import logging

from odoo import api, fields, models, _, SUPERUSER_ID
from odoo.api import constrains
from odoo.exceptions import ValidationError, AccessError

_logger = logging.getLogger(__name__)


class StockPicking(models.Model):
    _inherit = 'stock.picking'

    picking_type_name = fields.Char('picking type name', compute='get_picking_type_name', store=True)
    res_order = fields.Reference(string=u'Source', selection='_reference_models')
    apply_id = fields.Many2one('product.apply', string='Apply')
    work_station_id = fields.Many2one('work.station', )
    # 送货单号
    delivery_no = fields.Char(string='Delivery No')
    apply_uid = fields.Many2one('res.users', string='apply uid')
    apply_department_id = fields.Many2one(
        'hr.department', string='Department', related='apply_id.department_id', store=True)

    s_station_required = fields.Boolean('station required', compute='_compute_station_required')

    @api.depends('location_dest_id', 'picking_type_id')
    def _compute_station_required(self):
        production_location_ids = self.env['stock.location'].search([('barcode', '=', 'WH-PREPRODUCTION')], limit=1)
        production_location_ids |= production_location_ids.mapped('child_ids')
        loss = self.env['stock.location'].search([('barcode', '=', 'INVENTORY-lOSS')], limit=1)
        for rec in self:
            if rec.picking_type_id.barcode and rec.picking_type_id.barcode == 'WTT-PC':
                rec.s_station_required = False
                continue
            if rec.location_dest_id in production_location_ids:
                rec.s_station_required = True
            elif loss and rec.location_dest_id in loss:
                rec.s_station_required = True
            else:
                rec.s_station_required = False

    @api.model
    def _reference_models(self):
        return [('product.apply', 'Product Apply')]

    @api.depends('picking_type_id')
    def get_picking_type_name(self):
        for item in self:
            item.picking_type_name = item.picking_type_id.code

    def _create_backorder(self):
        """继承父类的 _create_backorder 方法，在创建回单时为每个 move.line 自动生成批次号"""
        # 这个鬼方法在wiz通过context赋值上下文再到stp _done function 中判断再传入到stock.move中_done function 再执行stp下的此方法
        backorders = self.env['stock.picking']
        bo_to_assign = self.env['stock.picking']

        # 使用 super 调用父类的 _create_backorder 方法
        for picking in self:
            moves_to_backorder = picking.move_ids.filtered(lambda x: x.state not in ('done', 'cancel'))
            moves_to_backorder._recompute_state()

            if moves_to_backorder:
                # 调用父类的方法来创建回单
                backorder_picking = super(StockPicking, self)._create_backorder()
                if picking.picking_type_name == 'incoming':
                    # 为每个库存移动行生成批次号
                    for move in moves_to_backorder:
                        for move_line in move.move_line_ids:
                            seq_rec = self.env['ir.sequence'].sudo().search([('code', '=', 'stock.lot.serial')],
                                                                            limit=1)
                            if seq_rec:
                                move_line.lot_name = seq_rec._next()  # 生成批次号并赋值

                # 将生成的回单发货单加入 backorders 集合
                backorders |= backorder_picking
                picking.message_post(
                    body=_('The backorder %s has been created.', backorder_picking._get_html_link())
                )

                if backorder_picking.picking_type_id.reservation_method == 'at_confirm':
                    bo_to_assign |= backorder_picking

        # 分配库存
        if bo_to_assign:
            bo_to_assign.action_assign()

        return backorders

    def action_confirm(self):
        # if not self.env.user.has_group('stock.group_stock_manager'):
        #     raise AccessError(_('You do not have permission to confirm the transfer order!'))

        # 2025-04-14 采购入库不再自动生成批次
        super(StockPicking, self).action_confirm()
        for item in self:
            for line in item.move_ids_without_package:
                if not line.product_uom_qty:
                    raise ValidationError(_("Please fill in the demand of product: '%s'" % line.product_id.name))
                # if item.picking_type_name == 'incoming':
                #     for move_line in line.move_line_ids:
                #         seq_rec = self.env['ir.sequence'].sudo().search([('code', '=', 'stock.lot.serial')],
                #                                                         limit=1)
                #         if not seq_rec:
                #             continue
                #         move_line.lot_name = seq_rec._next()

    def button_validate(self):
        if not self.env.user.has_group('stock.group_stock_user'):
            raise AccessError(_('You do not have permission to verify the transfer order!'))
        # res = super(StockPicking, self).button_validate()
        for item in self:
            for line in item.move_ids_without_package:
                if item.picking_type_name == 'outgoing':
                    for move_line in line.move_line_ids:
                        # 查找可用的批次
                        if not move_line.lot_id:
                            domain = [
                                ('available_quantity', '>', 0),
                                ('on_hand', '=', True),
                                ('quantity', '>', 0),
                                ('location_id', '=', line.location_id.id),
                                ('product_id', '=', line.product_id.id)
                            ]
                            quants = self.env['stock.quant'].sudo().search(domain, order='id')
                            product_uom_qty = line.quantity
                            move_line_vals = []
                            lot_ids = []
                            for quant in quants:
                                # 如果批次有lot_id
                                if not quant.lot_id:
                                    continue
                                if product_uom_qty <= quant.available_quantity:
                                    move_line.lot_id = quant.lot_id
                                    product_uom_qty = 0
                                    break
                                elif product_uom_qty and quant.available_quantity:
                                    move_line = self.env['stock.move.line'].create({
                                        'quant_id': quant.id,
                                        'location_id': line.location_id.id,
                                        'location_dest_id': line.location_dest_id.id,
                                        'quantity': quant.available_quantity,
                                        'product_uom_id': line.product_uom.id,
                                        'date': fields.Datetime.now(),
                                        'reference': line.name,
                                        'move_id': line.id,
                                        'lot_id': quant.lot_id.id
                                    })
                                    move_line_vals.append(move_line.id)
                                    lot_ids.append(quant.lot_id.id)
                                    product_uom_qty -= quant.available_quantity

                            # 如果仍然有剩余数量且没有足够的批次，抛出错误
                            if product_uom_qty > 0:
                                raise ValidationError(
                                    _('Product {} is out of stock or lacks enough batches to fulfill the delivery.'.format(
                                        line.product_id.name)))

        return super().button_validate()

    def action_release_materials(self):
        records = self.env['stock.picking'].browse(
            self._context.get('active_ids', []))
        for rec in records:
            if rec.state == 'done':
                raise ValidationError(_("The order '%s' has been completed") % rec.name)
            elif rec.state == 'cancel':
                raise ValidationError(_("The order '%s' has been cancelled") % rec.name)
            elif rec.state == 'draft':
                rec.action_confirm()
                rec.action_assign()
                rec.button_validate()
            else:
                rec.action_assign()
                rec.button_validate()
        return {
            'type': 'ir.actions.client',
            'tag': 'display_notification',
            'params': {
                'type': 'success',
                'title': _("Material sent successfully"),
                'next': {
                    'type': 'ir.actions.act_window_close'
                },
            }
        }

    @api.constrains('state')
    def onchange_delivery_no(self):
        for item in self:
            """将送货单号同步至批次中"""
            if item.state == 'done':
                for rec in item.move_line_ids:
                    if rec.lot_id:
                        rec.lot_id.update({
                            'delivery_no': item.delivery_no
                        })

    def apply_withdraw(self):
        """
        物料申领单撤回
         -可撤回状态 not in [done, cancel]
         -撤回后申领单置为草稿, 审批流置空
        """
        self.ensure_one()
        self = self.sudo()
        apply_id = self.apply_id
        if not apply_id:
            return
        if self.state in ['done', 'cancel']:
            raise ValidationError(_("The order '%s' has been completed or cancelled") % self.name)
        # 接触审批流
        apply_id.sb_workflow_ids.write({'active': False})
        apply_id.write({'sb_workflow_ids': [(3, apply_id.sb_workflow_id.id)]})
        # 更改主单状态
        apply_id.write({
            'sb_workflow_id': False,
            'state': 'draft'
        })
        self.action_cancel()

    @api.model
    def create(self, vals_list):
        pickings = super().create(vals_list)
        # 检查创建调拨单权限,仅为仓库管理员可创建调拨单
        if 'WTT-INTERNAL' in pickings.picking_type_id.mapped('barcode'):
            if not any([self.env.is_superuser(), self.env.user.has_group('stock.group_stock_manager')]):
                raise ValidationError(_("You don't have permission to create transfer order"))
        return pickings
